package acc_controllers

import (
	"chat-room/providers"
	"chat-room/websocket/acc_service"
	"sync"
)

// 连接管理器
type ClientManager struct {
	Clients     map[*Client]bool   // 全部连接
	ClientsLock sync.RWMutex       // 读写锁
	UserTokens  map[string]*Client // 全部连接
	UserLock    sync.RWMutex       // 读写锁
	Register    chan *Client       // 连接连接处理
	Unregister  chan *Client       // 断开连接处理程序
	Broadcast   chan *BroadcastMsg // 广播 向全部成员发送数据
}

// 广播消息
type BroadcastMsg struct {
	UserTokens []string // 广播对象
	Msg        []byte   // 消息内容
}

// 初始化管理器
func NewClientManager() (clientManager *ClientManager) {
	clientManager = &ClientManager{
		Clients:    make(map[*Client]bool),
		UserTokens: make(map[string]*Client),
		Register:   make(chan *Client, 1000),
		Unregister: make(chan *Client, 1000),
		Broadcast:  make(chan *BroadcastMsg, 1000),
	}
	return
}

/**
 * @Author: yang
 * @Description：事件监听
 * @Date: 2021/10/28 19:46
 */
func (cm *ClientManager) Start() {
	for {
		select {
		case conn := <-cm.Register:
			// 建立连接事件
			cm.EventRegister(conn)

		case conn := <-cm.Unregister:
			// 断开连接事件
			cm.EventUnregister(conn)

		case broadcastMsg := <-cm.Broadcast:
			// 广播事件信息
			cm.EventBroadcast(broadcastMsg)
		}

	}
}

/**************************  manager event管理  ***************************************/

/**
 * @Author: yang
 * @Description：创建连接事件
 * @Date: 2021/10/29 10:23
 */
func (cm *ClientManager) EventRegister(client *Client) {
	//providers.Logger.Info("EventRegister 用户建立连接 addr:" + client.Addr + " ; token : " + client.UserToken)
	// 建立连接
	cm.AddClient(client)

	// 系统消息同步--消息入库
	msg := "进入聊天室"
	logService := new(acc_service.LogService)
	err := logService.SaveLog(msg, client.UserToken, 2)
	if err != nil {
	_:
		providers.Logger.Error("聊天记录入库失败", err)
	}

	// 系统消息同步--格式化消息
	sendMsg := logService.ProductLog(msg, client.UserToken, 2)

	// 系统消息同步--推送本房间内所有人
	userService := new(acc_service.UserService)
	userTokenList := userService.GetUserTokenList(client.UserToken)
	if userTokenList != nil {
		clientManger.Broadcast <- &BroadcastMsg{
			UserTokens: userTokenList,
			Msg:        []byte(sendMsg),
		}
	}
}

/**
 * @Author: yang
 * @Description：断开连接事件
 * @Date: 2021/10/29 11:08
 */
func (cm *ClientManager) EventUnregister(client *Client) {
	providers.Logger.Info("EventUnregister 用户断开连接 addr:" + client.Addr + " ; token : " + client.UserToken)
	cm.DeleteClient(client)

	// 消息同步--消息入库
	msg := "离开聊天室"
	logService := new(acc_service.LogService)
	err := logService.SaveLog(msg, client.UserToken, 2)
	if err != nil {
	_:
		providers.Logger.Error("聊天记录入库失败", err)
	}

	// 系统消息同步--格式化消息
	sendMsg := logService.ProductLog(msg, client.UserToken, 2)

	// 消息同步--推送本房间内所有人
	userService := new(acc_service.UserService)
	userTokenList := userService.GetUserTokenList(client.UserToken)
	if userTokenList != nil {
		clientManger.Broadcast <- &BroadcastMsg{
			UserTokens: userTokenList,
			Msg:        []byte(sendMsg),
		}
	}
}

/**
 * @Author: yang
 * @Description：广播事件(根据token广播)
 * @Date: 2021/10/29 11:16
 */
func (cm *ClientManager) EventBroadcast(broadcastMsg *BroadcastMsg) {
	// 广播对象为空（全量广播）
	clientsAll := cm.GetClientsAll()

	// 推送指定客户端
	if len(broadcastMsg.UserTokens) > 0 {
		clientsSend := make(map[*Client]bool)
		for _, userToken := range broadcastMsg.UserTokens {
			for client := range clientsAll {
				if client.UserToken == userToken {
					clientsSend[client] = true
				}
			}
		}
		clientsAll = clientsSend
	}

	// @Todo 推送到集群中

	// 广播信息（推向client send 管道）
	for conn := range clientsAll {
		select {
		case conn.Send <- broadcastMsg.Msg:
		default:
			// @Todo 推送队列已经满了 -- 消息将丢失
		_:
			providers.Logger.Error("广播信息（推向client send 管道）推送管道满了UserToken ：", conn.UserToken)
		}
	}
}

/**************************  manager action 管理  ***************************************/

/**
 * @Author: yang
 * @Description：添加client连接
 * @Date: 2021/11/1 19:31
 */
func (cm *ClientManager) AddClient(client *Client) {
	// map 安全
	cm.ClientsLock.Lock()
	defer cm.ClientsLock.Unlock()

	// 添加client连接
	cm.Clients[client] = true

	return
}

/**
 * @Author: yang
 * @Description：删除client连接
 * @Date: 2021/11/1 19:38
 */
func (cm *ClientManager) DeleteClient(client *Client) {
	// map 安全
	cm.ClientsLock.Lock()
	defer cm.ClientsLock.Unlock()

	// 刪除连接
	if _, ok := cm.Clients[client]; ok {
		delete(cm.Clients, client)
	}
	return
}

/**
 * @Author: yang
 * @Description：获取全部可用连接
 * @Date: 2021/11/1 11:00
 */
func (cm *ClientManager) GetClientsAll() (clients map[*Client]bool) {
	clients = make(map[*Client]bool)

	cm.ClientsRange(func(key *Client, value bool) (result bool) {
		clients[key] = value
		return true
	})
	return
}

/**
 * @Author: yang
 * @Description：遍历客户端
 * @Date: 2021/11/1 10:56
 */
func (cm *ClientManager) ClientsRange(f func(client *Client, value bool) (result bool)) {

	cm.ClientsLock.RLock()
	defer cm.ClientsLock.RUnlock()

	for key, value := range cm.Clients {
		result := f(key, value)
		if result == false {
			return
		}
	}
}
